#include "cpu/exec/helper.h"

#define DATA_BYTE 1
#include "mov-template.h"
#undef DATA_BYTE

#define DATA_BYTE 2
#include "mov-template.h"
#undef DATA_BYTE

#define DATA_BYTE 4
#include "mov-template.h"
#undef DATA_BYTE

/* for instruction encoding overloading */

make_helper_v(mov_i2r)
make_helper_v(mov_i2rm)
make_helper_v(mov_r2rm)
make_helper_v(mov_rm2r)
make_helper_v(mov_a2moffs)
make_helper_v(mov_moffs2a)

make_helper(mov_rm_l){
    int len = decode_rm_l(eip + 1);
    if(ops_decoded.opcode == 0x120){
        switch(op_src2->reg){
            case 0:
            reg_l(op_src->reg) = cpu.cr0.val;
            print_asm(str(mov) " cr0 %s", op_src->str);
            break;
            case 1:
            panic("have no cr1 yet in mov\n");
            break;
            case 2:
            panic("have no cr2 yet in mov\n");
            break;
            case 3:
            reg_l(op_src->reg) = cpu.cr3.val;
            print_asm(str(mov) " cr3 %s", op_src->str);
            break;
            default:
            panic("in mov_rm_l\n");
        }
    }
    else if(ops_decoded.opcode == 0x122){
        switch(op_src2->reg){
            case 0:
            cpu.cr0.val = reg_l(op_src->reg);
            print_asm(str(mov) " %s cr0", op_src->str);
            break;
            case 1:
            panic("have no cr1 yet in mov\n");
            break;
            case 2:
            panic("have no cr2 yet in mov\n");
            break;
            case 3:
            cpu.cr3.val = reg_l(op_src->reg);
            print_asm(str(mov) " %s cr3", op_src->str);
            break;
            default:
            panic("in mov_rm_l\n");
        }
        
    }
    
    return len + 1;
}

make_helper(mov_cr2r) {
  uint8_t modrm = instr_fetch(eip + 1, 1);
  uint8_t cr_num = (modrm >> 3) & 7;
  uint8_t reg_num = modrm & 7;
  switch (cr_num) {
  case 0:
    reg_l(reg_num) = cpu.cr0.val;
    print_asm("mov CR0 %s", regsl[reg_num]);
    break;
  case 3:
    reg_l(reg_num) = cpu.cr3.val;
    print_asm("mov CR3 %s", regsl[reg_num]);
  default:
    break;
  }
  return 2;
}

make_helper(mov_r2cr) {
  uint8_t modrm = instr_fetch(eip + 1, 1);
  uint8_t cr_num = (modrm >> 3) & 7;
  uint8_t reg_num = modrm & 7;
  switch (cr_num) {
  case 0:
    cpu.cr0.val = reg_l(reg_num);
    print_asm("mov %s CR0", regsl[reg_num]);
    break;
  case 3:
    //init_tlb();
    cpu.cr3.val = reg_l(reg_num);
    print_asm("mov %s CR3", regsl[reg_num]);
    break;
  default:
    break;
  }
  return 2;
}
